﻿using System.Collections.Generic;
using PloobsEngine.SceneControl;
using PloobsEngine.Physics;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Input;
using Microsoft.Xna.Framework;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine.Features;
using PloobsEngine.Commands;
using PloobsEngine.Draw;
using PloobsEngine.Light;
using Etapa1.Pedestrian;
using PloobsEngine.IA;
using Microsoft.Xna.Framework.Input;
using Bnoerj.AI.Steering;
using Bnoerj.AI.Steering.Pedestrian;

namespace Etapa1.Screens
{
    public class PathSteerFindingScreen : SceneScreen
    {
        private BepuPhysicWorld physicWorld;
        private BrutalForceWorld mundo;
        private EngineStuff engine;                
        ICamera cam;        
        Vector3 pos = new Vector3(100, 3, 100);        
        PathManager pm;
        SimpleMap sm;
        AStar astar;
        SteerPathPlugIn plugin;

        public PathSteerFindingScreen(EngineStuff es)
        {
            this.engine = es;
            physicWorld = new BepuPhysicWorld();            
            mundo = new BrutalForceWorld(physicWorld);             
            engine.Game.IsFixedTimeStep = true;
        }
       
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Space))
            {
                CreateWaypoints();
                wh.DebugDrawWaypointsVector();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Enter))
            {
                ConnectWaypoints();
                Drawing.ClearAll();
                wh.DebugDrawWaypointsVector();

                Drawing.Draw3dLine(pos, pos + Vector3.Up * 20, Color.Green);
                Drawing.DrawCircleOrDisk(10, Vector3.Up, pos, Color.Green, 100, true,true);

                foreach (var item in pm.Obstacles)
                {
                    Drawing.DrawXZCircle(item.Radius, item.Center, Color.White, 40);                    
                }
                
            }

            if (Keyboard.GetState().IsKeyDown(Keys.RightShift))
            {
                Drawing.ClearAll();
            }

            if (Keyboard.GetState().IsKeyDown(Keys.RightControl))
            {
                Drawing.Draw3dLine(pos, pos + Vector3.Up * 20, Color.Green);
                Drawing.DrawCircleOrDisk(10, Vector3.Up, pos, Color.Green, 100, true, true);

                foreach (var item in pm.Obstacles)
                {
                    Drawing.DrawXZCircle(item.Radius, item.Center, Color.White, 40);                
                }
            }

            plugin.Update(EngineStuff.Clock.TotalSimulationTime, EngineStuff.Clock.ElapsedSimulationTime);
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);					
        }

        public override void LoadContent(EngineStuff es)
        {
            base.LoadContent(es);

            InputAdvanced inp = new InputAdvanced(engine);
            engine.AddComponent(inp);

            Picking pk = new Picking();
            engine.AddComponent(pk);

            Drawing.setClearEveryFrame(false);

            pm = new PathManager(new List<Vector3>() { }, 1);
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\blue");
                sm.LoadModelo();
                BoxObject pi = new BoxObject(new Vector3(0, -5, 100), 1, new Vector3(900, 5, 900));
                pi.isMotionLess = true;
                IShader shader = new NormalDeferred();
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
            }

            ///Obstaculos
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                BoxObject pi = new BoxObject(new Vector3(0, 1, 0), 1, new Vector3(3, 20, 40));
                pi.isMotionLess = true;
                IShader shader = new NormalDeferred();
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
                pm.AddCircularObstacle(obj4);
            }

            ///Obstaculos
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                BoxObject pi = new BoxObject(new Vector3(-200, 1, 100), 1, new Vector3(30, 20, 3));
                pi.isMotionLess = true;
                IShader shader = new NormalDeferred();
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
                pm.AddCircularObstacle(obj4);
            }

            ///Obstaculos
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                BoxObject pi = new BoxObject(new Vector3(-40, 1, 180), 1, new Vector3(30, 20, 3));
                pi.isMotionLess = true;
                IShader shader = new NormalDeferred();
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
                pm.AddCircularObstacle(obj4);
            }

            ///Obstaculos
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                BoxObject pi = new BoxObject(new Vector3(0, 1, 150), 1, new Vector3(35, 20, 5));
                pi.isMotionLess = true;
                IShader shader = new NormalDeferred();
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
                pm.AddCircularObstacle(obj4);
            }

            ///Obstaculos
            {
                SimpleModel sm = new SimpleModel("..\\Content\\Model\\block", "..\\Content\\Textures\\white");
                sm.LoadModelo();
                BoxObject pi = new BoxObject(new Vector3(-340, 1, -150), 1, new Vector3(65, 20, 5));
                pi.isMotionLess = true;
                IShader shader = new NormalDeferred();
                shader.Initialize();
                IMaterial mat = new Material(shader, MaterialType.DEFERRED);
                IObject obj4 = new SimpleObject(mat, pi, sm);
                mundo.AddObject(obj4);
                pm.AddCircularObstacle(obj4);
            }


            cam = new CameraFirstPerson(true);
            cam.FarPlane = 3000;

            plugin = new SteerPathPlugIn(mundo, engine);
            plugin.Open();

            //LightThrowBepu lt = new LightThrowBepu(mundo, engine);       

            #region LIGHT
            DirectionalLight ld = new DirectionalLight(new Vector3(-1), Color.White);
            DirectionalLight ld2 = new DirectionalLight(new Vector3(-0.3f, -1, -0.3f), Color.White);
            DirectionalLight ld3 = new DirectionalLight(Vector3.Down, Color.White);
            ld.LightIntensity = 0.3f;
            ld2.LightIntensity = 0.3f;
            ld3.LightIntensity = 0.3f;
            mundo.AddLight(ld);
            mundo.AddLight(ld2);
            mundo.AddLight(ld3);
            #endregion

            
            DeferredRenderTechnic dr = new DeferredRenderTechnic(engine);
            IRenderTechnic[] rt = new IRenderTechnic[] { dr };
            this.RenderTechnics = rt;
            mundo.AddCamera(cam);
            this.World = mundo;

            {
                PickingParameters pp = new PickingParameters(cam, mundo, MouseButtons.RightButton);
                pp.Method = SegmentInterceptMethod.ALL;
                PickingRedirectorCallbackObserver prc = new PickingRedirectorCallbackObserver();
                prc.redirectPicking += new RedirectPicking(prc_redirectPicking);
                pp.Observers.Add(prc);
                CommandProcessor.getCommandProcessor().SendCommandSyncronous(pp);
            }
            {
                PickingParameters pp = new PickingParameters(cam, mundo, MouseButtons.LeftButton);
                pp.Method = SegmentInterceptMethod.ALL;
                PickingRedirectorCallbackObserver prc = new PickingRedirectorCallbackObserver();
                prc.redirectPicking += new RedirectPicking(prc_redirectPicking2);
                pp.Observers.Add(prc);
                CommandProcessor.getCommandProcessor().SendCommandSyncronous(pp);      
            }

            Drawing.Draw3dLine(pos, pos + Vector3.Up * 20, Color.Green);
            Drawing.DrawCircleOrDisk(10, Vector3.Up, pos, Color.Green, 100, true, true);

            foreach (var item in pm.Obstacles)
            {
                Drawing.DrawXZCircle(item.Radius, item.Center, Color.White, 40);
                //   Drawing.DrawXZCircle(item.Radius, item.Center, Color.White, 40);		    
            }
 

        }

        void prc_redirectPicking2(object obj)
        {
            RayTestInfo ri = obj as RayTestInfo;
            if (ri != null)
            {
                wh.AddWaypoint(ri.ImpactPosition, WAYPOINTTYPE.NORMAL);
                Drawing.Draw3dLine(ri.ImpactPosition, ri.ImpactPosition + Vector3.Up * 20, Color.Red);
            }
        }


        void prc_redirectPicking(object obj)
        {
            RayTestInfo ri = obj as RayTestInfo;

            WaypointsCollection wc = wh.GetWaypoints();
            sm = new SimpleMap(wc);
            astar = new AStar(sm);
            Waypoint wp0 = sm.GetClosestWaypoint(pos);
            Waypoint wp1 = sm.GetClosestWaypoint(ri.ImpactPosition);
            LinkedList<Waypoint> path = astar.GetPath(AIWorkType.SINGLE_TIME, wp0, wp1);
            Waypoint s0 = new Waypoint();
            s0.WorldPos = pos;
            Waypoint s1 = new Waypoint();
            s1.WorldPos = ri.ImpactPosition;
            path.AddFirst(s0);
            path.AddLast(s1);

            Vector3[] vecs = new Vector3[path.Count];
            int i = 0;
            foreach (var item in path)
            {
                vecs[i++] = item.WorldPos;   
            }

            PolylinePathway testPath = new PolylinePathway(path.Count,
                                     vecs,
                                     10,
                                     false);            


            if(path == null || path.Count == 0) return;

            plugin.AddAgente(testPath, pm.Obstacles);

            Drawing.Draw3dLine(ri.ImpactPosition, ri.ImpactPosition + Vector3.Up * 20, Color.Red);
            Drawing.DrawCircleOrDisk(5, Vector3.Up, ri.ImpactPosition, Color.Purple, 100, true, true);
            
        }

        WaypointHandler wh = new WaypointHandler("teste");                
        int space = 100;
        int mapSizeX = 500 ;
        int mapSizeZ = 500;

        public void ClearWaypoints()
        {
            wh.Init("teste", "teste.xml");
        }

        public void CreateWaypoints()
        {
            for (int i = -mapSizeX/2; i < mapSizeX/2; i+=space)
			{			 
                for (int j = -mapSizeZ/2; j < mapSizeZ/2; j+=space)
			    {
                    wh.AddWaypoint(new Vector3(i, 0, j), WAYPOINTTYPE.NORMAL);       		 
			    }
			}
        }        

        public void ConnectWaypoints()
        {
            VisibilityWaypointConnector vw = new VisibilityWaypointConnector(mundo);
            vw.Altura = 5;
            vw.MaxDistance = 150;
            wh.ConnectWaypoints(vw); 
        }

    }
}

